#include "CollisionManager.h"

CollisionManager::CollisionManager(void)
{
	//data.reserve(20000);
}

CollisionManager::~CollisionManager(void)
{
}

CollisionData::CollisionData(GameObject **a, GameObject **b, FatBase<void> *f, unsigned int t):
objectA(a),
objectB(b),
function(f),
type(t)
{
}

CollisionData::~CollisionData(){};

void CollisionManager::setDetection(GameObject *& a, GameObject *& b, FatBase<void> *function, unsigned int type)
{
	/*objectA.push_back( &(a) );
	objectB.push_back( &(b) );
	functions.push_back(function);*/

	CollisionData *d = new CollisionData(&a, &b, function, type);
	data.push_back( d );
}

/*void CollisionManager::removeDetection(unsigned int n)
{
	//delete data[n];
	//data.erase(data.begin() + n );
	CollisionData *d;
	d = data.back();
	data.back() = data[n];
	data[n] = d;
	data.pop_back();
}*/

void CollisionManager::update()
{
	/*for(unsigned int i = 0; i < data.size(); ++i)
	{
		if( !(*data[i]->objectA) || !(*data[i]->objectB) )
		{
			removeDetection(i);
		}
		else
		{
			if(data[i]->type == 1)
			{
				if(BBCollision(*data[i]->objectA, *data[i]->objectB))
					data[i]->function->callMethod( data[i]->objectA, data[i]->objectB );
			}
			else
			{
				if(pointCollision(*data[i]->objectA, *data[i]->objectB))
					data[i]->function->callMethod( data[i]->objectA, data[i]->objectB );
			}
		}
	}*/

	//optymalizacja ?

	std::list <CollisionData*>::iterator it;

	for(it = data.begin(); it != data.end();)
	{
		if( !(*(*it)->objectA) || !(*(*it)->objectB) )
		{
			//removeDetection( it - data.begin());
			it = data.erase(it);
			//--it;
		}
		else
		{
			if( (*it)->type == 1 )
			{
				if( pointCollision( *(*it)->objectA, *(*it)->objectB ) )
					(*it)->function->callMethod( (*it)->objectA, (*it)->objectB );
			}
			else if( (*it)->type == 2 )
			{
				if( BBCollision( *(*it)->objectA, *(*it)->objectB ) )
					(*it)->function->callMethod( (*it)->objectA, (*it)->objectB );
			}
			else if( (*it)->type == 3 )
			{
				if( sensorCollision( *(*it)->objectA, *(*it)->objectB ) )
					(*it)->function->callMethod( (*it)->objectA, (*it)->objectB );
			}

			++it;
		}
	}

}

bool CollisionManager::BBCollision(GameObject *a, GameObject *b)
{
	/*int left1, left2;
    int right1, right2;
    int top1, top2;
    int bottom1, bottom2;

    left1 = a->x;
    left2 = b->x;
    right1 = left1 + a->width;
    right2 = left2 + b->width;
    top1 = a->y;
    top2 = b->y;
    bottom1 = top1 + a->height;
    bottom2 = top2 + b->height;

    if (bottom1 < top2) return(0);
    if (top1 > bottom2) return(0);
  
    if (right1 < left2) return(0);
    if (left1 > right2) return(0);

    return(1);*/

	//optymalizacja?
	if ( (a->y + a->height) < b->y) return(0);
    if ( a->y > (b->y + b->height) ) return(0);
  
	if ( (a->x + a->width) < b->x) return(0);
    if ( a->x > ( b->x + b->width) ) return(0);

    return(1);

}

bool CollisionManager::pointCollision(GameObject *a, GameObject *b)
{
	return ( (a->x > b->x) && (a->x < (b->x + b->width)) && (a->y > b->y) && (a->y < (b->y + b->height)) );
}

bool CollisionManager::sensorCollision(GameObject *a, GameObject *b)
{
	b2ContactEdge *list =  static_cast<PhysicObject*>(b)->body->GetContactList();
	while(list)
	{
		if(list->contact->IsTouching() && (list->contact->GetFixtureB()->GetBody() == static_cast<PhysicObject*>(a)->body || list->contact->GetFixtureA()->GetBody() == static_cast<PhysicObject*>(a)->body) )
			return true;
		list = list->next;
	}
	return false;
}

void CollisionManager::clearAll()
{
	/*for(unsigned int i = 0; i < data.size(); ++i)
	{
		removeDetection(i);
	}*/
	std::list <CollisionData*>::iterator it;

	for(it = data.begin(); it != data.end();)
	{
		delete *it;
	}
	data.clear();
}

